package com.blue.wechat.invoke;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.task.TaskExecutor;

import com.blue.core.file.ClassScanner;
import com.blue.core.util.BeanUtil;
import com.blue.wechat.invoke.annotation.WechatInvokerClassHandler;
import com.blue.wechat.invoke.annotation.WechatUrl;

/**
 * 微信接口调用入口
 * 
 * @author zhengj
 * @since 1.0 2017年1月25日
 */
public class WechatContainer implements InitializingBean, ApplicationContextAware
{
	private static Logger logger = LoggerFactory.getLogger(WechatContainer.class);

	@Autowired(required = false)
	@Qualifier("taskExecutor")
	private TaskExecutor taskExecutor;
	
	private ApplicationContext ctx;
	private Map<WechatInvoker, Invoker<?>> invokerMap = new ConcurrentHashMap<>();

	public WechatContainer()
	{
	}
	
	/**
	 * 根据代码获取服务调用实例
	 * 
	 * @param key 微信接口
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> Invoker<T> get(WechatInvoker key)
	{
		Invoker<T> invoker = (Invoker<T>)invokerMap.get(key);
		if (invoker == null)
			throw InvokeException.getException(InvokeException.WECHAT_URL_NOT_FOUND + key.getName());
		
		return invoker;
	}
	
	/**
	 * 调用微信服务
	 * 
	 * @param code 微信代码
	 * @param key 微信接口
	 * @param post POST数据
	 * @param get GET参数
	 */
	public <T> T invoke(String code, WechatInvoker key, Object post, String...get)
	{
		Invoker<T> invoker = this.get(key);
		
		return invoker.invoke(code, post, get);
	}
	
	/**
	 * 异步调用微信服务
	 * 
	 * @param code 微信代码
	 * @param key 微信接口
	 * @param post POST数据
	 * @param get GET参数
	 */
	public <T> void asyncInvoke(String code, WechatInvoker key, Object post, String...get)
	{
		if (taskExecutor == null)
			throw InvokeException.getException(InvokeException.UNSUPPORTED_ASYNC);
		
		Invoker<T> invoker = this.get(key);
		
		taskExecutor.execute(() -> invoker.invoke(code, post, get));
	}

	/**
	 * 解析微信接口类
	 * 
	 * @param clazz 微信接口实现类 
	 */
	public void parse(Class<?> clazz)
	{
		WechatUrl annoUrl = clazz.getAnnotation(WechatUrl.class);
		if (annoUrl == null)
			throw new IllegalArgumentException(clazz.getName() + " 缺少 @WechatUrl 注解");

		WechatInvoker key = annoUrl.value();
		Invoker<?> invoker = BeanUtil.initBean(clazz, Invoker.class, ctx);
		invokerMap.put(key, invoker);
		logger.info("找到微信接口：{}－{}－{}", key.name(), key.getName(), clazz.getName());
	}

	@Override
	public void setApplicationContext(ApplicationContext ctx) throws BeansException
	{
		this.ctx = ctx;
	}

	@Override
	public void afterPropertiesSet() throws Exception
	{
		ClassScanner scanner = new ClassScanner();
		scanner.setClassHandler(new WechatInvokerClassHandler(this));
		scanner.scan(true, "com.blue.wechat.invoke.spi");
		
	}

}
